<?php
class system_controller_router_route implements system_controller_router_route_interface {
	
	protected $_route = null;
	protected $_defaults = array();
	protected $_reverse = null;
	protected $_map = array();
	protected $_values = array();
	protected $_ssl;
	
	public function __construct($route, $reverse, array $defaults = array(), array $map = array(), $ssl = null) {
		$this->_route = $route;
		$this->_defaults = $defaults;
		$this->_reverse = $reverse;
		$this->_map = $map;
		$this->_ssl = $ssl;
	}
	
	public function match($path) {		
		$route = $this->_route;
		$path = trim(urldecode($path), '/');		
		$return = array();
		//固定地址对比
		if(strtolower($route) == strtolower($path)) {
			return $this->_getMappedValues($this->_defaults);
		}		
		$regex = '#^' . $this->_route . '$#i';		
		$res = preg_match($regex, $path, $values);		
		if($res === 0) {
			return false;
		}
		foreach($values as $i => $value) {
			if(!is_int($i) || $i === 0) {
				unset($values[$i]);
			}
		}
		$this->_values = $values;
		$values = $this->_getMappedValues($values);
		$defaults = $this->_getMappedValues($this->_defaults, false, true);
		$return = $values + $defaults;
		return (array) $return;
	}
	
	public function getDefault($name) {
		return isset($this->_defaults[$name]) ? $this->_defaults[$name] : null;
	}
	/**
	 * 根据map的关系，将值和健组合.
	 */
	protected function _getMappedValues($values, $reversed = false, $preserve = false) {
		if(count($this->_map) == 0) {
			return $values;
		}		
		$return = array();		
		foreach($values as $key => $value) {
			if(is_int($key) && !$reversed) {
				if(array_key_exists($key, $this->_map)) {
					$index = $this->_map[$key];
				} elseif(false === ($index = array_search($key, $this->_map))) {
					$index = $key;
				}
				$return[$index] = $values[$key];
			} elseif($reversed) {
				$index = $key;
				if(!is_int($key)) {
					if(array_key_exists($key, $this->_map)) {
						$index = $this->_map[$key];
					} else {
						$index = array_search($key, $this->_map, true);
					}
				}
				if(false !== $index) {
					$return[$index] = $values[$key];
				}
			} elseif($preserve) {
				$return[$key] = $value;
			}
		}
		return $return;
	}
	
	//将数组2 替换到 array1中,并合并反回
	protected function _arrayMergeNumericKeys(Array $array1, Array $array2) {
		$returnArray = $array1;
		foreach($array2 as $array2Index => $array2Value) {
			$returnArray[$array2Index] = $array2Value;
		}
		return $returnArray;
	}
	
	public function assemble($data = array(), $reset = false, $encode = false, $partial = false) {
		if($this->_reverse === null) {
			throw new system_controller_router_exception('Cannot assemble. Reversed route is not specified.');
		}
		
		$defaultValuesMapped = $this->_getMappedValues($this->_defaults, true, false);
		$matchedValuesMapped = $this->_getMappedValues($this->_values, true, false);
		$dataValuesMapped = $this->_getMappedValues($data, true, false);
		
		// handle resets, if so requested (By null value) to do so
		if(($resetKeys = array_search(null, $dataValuesMapped, true)) !== false) {
			foreach((array) $resetKeys as $resetKey) {
				if(isset($matchedValuesMapped[$resetKey])) {
					unset($matchedValuesMapped[$resetKey]);
					unset($dataValuesMapped[$resetKey]);
				}
			}
		}
		
		$mergedData = $defaultValuesMapped;
		//$mergedData = $this->_arrayMergeNumericKeys($mergedData, $matchedValuesMapped);
		//fix 默认的值高于params,因为当页面的某个参数没有给值时，使用默认值 ，而不是params里的值 ，
		//当默认值 没有时再用params
		$mergedData = $this->_arrayMergeNumericKeys($matchedValuesMapped, $mergedData);
		$mergedData = $this->_arrayMergeNumericKeys($mergedData, $dataValuesMapped);
		
		if($encode) {
			foreach($mergedData as $key => &$value) {
				$value = urlencode($value);
			}
		}		
		ksort($mergedData);		
		$return = @vsprintf($this->_reverse, $mergedData);		
		if($return === false) {
			throw new system_controller_router_exception('Cannot assemble. Too few arguments?');
		}		
		$url = trim(system_controller_front::getInstance()->getBaseUrl() . '/' . ltrim($return, '/'));
		if($this->_ssl === true && isset($_SERVER['SERVER_NAME'])) {
			$url = 'https://' . $_SERVER['SERVER_NAME'] . $url;
		} elseif($this->_ssl === false && isset($_SERVER['SERVER_NAME'])) {
			$url = 'http://' . $_SERVER['SERVER_NAME'] . $url;
		}
		return $url;
	}
}